use crate::{AsJValueArray, FromJValue, JClassID, JEnv, JLocal, JMethodID, JObject, JRc, JRefType, JWeak};

pub trait JNameMaker {
	const JAVA_PATH: &'static [u8];
	fn java_path() -> Option<&'static str> {
		core::ffi::CStr::from_bytes_with_nul(Self::JAVA_PATH).ok()?.to_str().ok()
	}
}

pub trait JPlainMarker: AsRef<JObject> + JNameMaker + Sized {
	fn class(env: Option<&JEnv>) -> Option<JClassID>;
	fn new_with<const N: usize>(env: &JEnv, method: JMethodID, args: impl AsJValueArray<N>) -> Option<&Self> {
		env.new_object(method, args)
	}
	fn instance_of(&self, class: JClassID, env: &JEnv) -> bool {
		env.is_instance_of(self.as_ref(), class) == Some(true)
	}
	fn is_eq(&self, other: &Self, env: &JEnv) -> bool {
		env.is_same_object(self.as_ref(), other.as_ref()) == Some(true)
	}
	fn ref_type(&self, env: &JEnv) -> JRefType {
		env.ref_type(self.as_ref())
	}
	fn local<'a, 'b: 'a>(&'a self, env: &'b JEnv) -> Option<JLocal<'a, Self>> {
		env.new_local(self)
	}
	fn weak(&self, env: &JEnv) -> Option<JWeak<Self>> {
		env.new_weak(self)
	}
	fn global(&self, env: &JEnv) -> Option<JRc<Self>> {
		env.new_global(self)
	}
}

pub enum JArrayPrimType {
	Bool,
	Byte,
	Char,
	Short,
	Int,
	Long,
	Float,
	Double,
}
pub trait JArrayPrimMaker: Clone + Copy {
	const TYPE: JArrayPrimType;
}
mod array_prim_maker {
	use crate::{JArrayPrimMaker, JArrayPrimType, JBool, JByte, JChar, JDouble, JFloat, JInt, JLong, JShort};

	impl JArrayPrimMaker for JBool {
		const TYPE: JArrayPrimType = JArrayPrimType::Bool;
	}
	impl JArrayPrimMaker for JByte {
		const TYPE: JArrayPrimType = JArrayPrimType::Byte;
	}
	impl JArrayPrimMaker for JChar {
		const TYPE: JArrayPrimType = JArrayPrimType::Char;
	}
	impl JArrayPrimMaker for JShort {
		const TYPE: JArrayPrimType = JArrayPrimType::Short;
	}
	impl JArrayPrimMaker for JInt {
		const TYPE: JArrayPrimType = JArrayPrimType::Int;
	}
	impl JArrayPrimMaker for JLong {
		const TYPE: JArrayPrimType = JArrayPrimType::Long;
	}
	impl JArrayPrimMaker for JFloat {
		const TYPE: JArrayPrimType = JArrayPrimType::Float;
	}
	impl JArrayPrimMaker for JDouble {
		const TYPE: JArrayPrimType = JArrayPrimType::Double;
	}
}

pub trait JReturnMaker: FromJValue {
	const RETURN_TYPE: JReturnType;
}
pub enum JReturnType {
	Void,
	Bool,
	Byte,
	Char,
	Short,
	Int,
	Long,
	Float,
	Double,
	Object,
}
mod return_maker {
	use crate::{
		JArray, JArrayObject, JArrayPrim, JArrayPrimMaker, JBool, JByte, JChar, JClassID, JDouble, JFloat, JInt, JLong, JObject,
		JPlainMarker, JReturnMaker, JReturnType, JShort,
	};

	impl JReturnMaker for () {
		const RETURN_TYPE: JReturnType = JReturnType::Void;
	}
	impl JReturnMaker for JBool {
		const RETURN_TYPE: JReturnType = JReturnType::Bool;
	}
	impl JReturnMaker for JByte {
		const RETURN_TYPE: JReturnType = JReturnType::Byte;
	}
	impl JReturnMaker for JChar {
		const RETURN_TYPE: JReturnType = JReturnType::Char;
	}
	impl JReturnMaker for JShort {
		const RETURN_TYPE: JReturnType = JReturnType::Short;
	}
	impl JReturnMaker for JInt {
		const RETURN_TYPE: JReturnType = JReturnType::Int;
	}
	impl JReturnMaker for JLong {
		const RETURN_TYPE: JReturnType = JReturnType::Long;
	}
	impl JReturnMaker for JFloat {
		const RETURN_TYPE: JReturnType = JReturnType::Float;
	}
	impl JReturnMaker for JDouble {
		const RETURN_TYPE: JReturnType = JReturnType::Double;
	}
	impl JReturnMaker for sys::jobject {
		const RETURN_TYPE: JReturnType = JReturnType::Object;
	}
	impl<T: AsRef<JObject> + JPlainMarker> JReturnMaker for &T {
		const RETURN_TYPE: JReturnType = JReturnType::Object;
	}
	impl JReturnMaker for &JArray {
		const RETURN_TYPE: JReturnType = JReturnType::Object;
	}
	impl<T: AsRef<JObject>> JReturnMaker for &JArrayObject<T> {
		const RETURN_TYPE: JReturnType = JReturnType::Object;
	}
	impl<T: JArrayPrimMaker> JReturnMaker for &JArrayPrim<T> {
		const RETURN_TYPE: JReturnType = JReturnType::Object;
	}
	impl JReturnMaker for JClassID {
		const RETURN_TYPE: JReturnType = JReturnType::Object;
	}
}

// pub trait JSignMaker {
// 	fn sign() -> impl crate::JSign;
// }
// mod prim_sign_maker {
// 	use crate::{
// 		JBool, JByte, JChar, JDouble, JFloat, JInt, JLong, JShort, JSignBool, JSignByte, JSignChar, JSignDouble, JSignFloat, JSignInt,
// 		JSignLong, JSignMaker, JSignShort, JSignVoid,
// 	};
// 	impl JSignMaker for () {
// 		fn sign() -> impl crate::JSign {
// 			JSignVoid
// 		}
// 	}
// 	impl JSignMaker for JBool {
// 		fn sign() -> impl crate::JSign {
// 			JSignBool
// 		}
// 	}
// 	impl JSignMaker for JByte {
// 		fn sign() -> impl crate::JSign {
// 			JSignByte
// 		}
// 	}
// 	impl JSignMaker for JChar {
// 		fn sign() -> impl crate::JSign {
// 			JSignChar
// 		}
// 	}
// 	impl JSignMaker for JShort {
// 		fn sign() -> impl crate::JSign {
// 			JSignShort
// 		}
// 	}
// 	impl JSignMaker for JInt {
// 		fn sign() -> impl crate::JSign {
// 			JSignInt
// 		}
// 	}
// 	impl JSignMaker for JLong {
// 		fn sign() -> impl crate::JSign {
// 			JSignLong
// 		}
// 	}
// 	impl JSignMaker for JFloat {
// 		fn sign() -> impl crate::JSign {
// 			JSignFloat
// 		}
// 	}
// 	impl JSignMaker for JDouble {
// 		fn sign() -> impl crate::JSign {
// 			JSignDouble
// 		}
// 	}
// }
// impl<T: JPlainMarker> JSignMaker for T {
// 	fn sign() -> impl crate::JSign {
// 		JSignRef(Self::NAME)
// 	}
// }
// impl<T: AsRef<JObject> + JSignMaker> JSignMaker for JArrayObject<T> {
// 	fn sign() -> impl crate::JSign {
// 		JSignArray(T::sign())
// 	}
// }
// impl<T: JArrayPrimMaker> JSignMaker for JArrayPrim<T> {
// 	fn sign() -> impl crate::JSign {
// 		JSignArray(T::sign())
// 	}
// }
